//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_recycle_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/api_coll_dao"
	"atomgit.com/openlinksaas/api-server/dao/bulletin_dao"
	"atomgit.com/openlinksaas/api-server/dao/comment_dao"
	"atomgit.com/openlinksaas/api-server/dao/data_anno_dao"
	"atomgit.com/openlinksaas/api-server/dao/idea_dao"
	"atomgit.com/openlinksaas/api-server/dao/issue_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_board_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_doc_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_entry_dao"
	"atomgit.com/openlinksaas/api-server/dao/requirement_dao"
	"atomgit.com/openlinksaas/api-server/dao/testcase_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_comment_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_entry_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_issue_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_recycle_api"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectRecycleApiImpl) Remove(ctx context.Context, req *project_recycle_api.RemoveRequest) (*project_recycle_api.RemoveResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_recycle_api.RemoveResponse{
			Code:   project_recycle_api.RemoveResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_recycle_api.RemoveResponse{
			Code:   project_recycle_api.RemoveResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_recycle_api.RemoveResponse{
			Code:   project_recycle_api.RemoveResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_recycle_api.RemoveResponse{
			Code:   project_recycle_api.RemoveResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_recycle_api.RemoveResponse{
			Code:   project_recycle_api.RemoveResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	recycleItem, err := project_dao.RecycleDao.Get(ctx, req.ProjectId, req.RecycleItemId)
	if err != nil { //记录不存在
		return &project_recycle_api.RemoveResponse{
			Code: project_recycle_api.RemoveResponse_CODE_OK,
		}, nil
	}

	title, err := apiImpl.getTitle(ctx, req.ProjectId, req.RecycleItemId, project_recycle_api.RECYCLE_ITEM_TYPE(recycleItem.RecycleItemType))
	if err != nil {
		return nil, err
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_dao.RecycleDao.Remove(sessCtx, req.ProjectId, req.RecycleItemId)
		if err != nil {
			return nil, err
		}
		if recycleItem.RecycleItemType == uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_IDEA) {
			err = apiImpl.removeIdea(sessCtx, projectItem, recycleItem.RecycleItemId)
			if err != nil {
				return nil, err
			}
		} else if recycleItem.RecycleItemType == uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_REQUIREMENT) {
			err = apiImpl.removeRequirement(sessCtx, projectItem, recycleItem.RecycleItemId)
			if err != nil {
				return nil, err
			}
		} else if recycleItem.RecycleItemType == uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_TASK) {
			err = apiImpl.removeIssue(sessCtx, projectItem, recycleItem.RecycleItemId, project_issue_api.ISSUE_TYPE_ISSUE_TYPE_TASK)
			if err != nil {
				return nil, err
			}
		} else if recycleItem.RecycleItemType == uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_BUG) {
			err = apiImpl.removeIssue(sessCtx, projectItem, recycleItem.RecycleItemId, project_issue_api.ISSUE_TYPE_ISSUE_TYPE_BUG)
			if err != nil {
				return nil, err
			}
		} else if recycleItem.RecycleItemType == uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_TESTCASE) {
			err = apiImpl.removeTestcase(sessCtx, projectItem, recycleItem.RecycleItemId)
			if err != nil {
				return nil, err
			}
		} else if recycleItem.RecycleItemType == uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_BULLETIN) {
			err = apiImpl.removeBulletin(sessCtx, projectItem, recycleItem.RecycleItemId)
			if err != nil {
				return nil, err
			}
		} else if recycleItem.RecycleItemType == uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_SPRIT) {
			err = apiImpl.removeSprit(sessCtx, projectItem, recycleItem.RecycleItemId)
			if err != nil {
				return nil, err
			}
		} else if recycleItem.RecycleItemType == uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_DOC) {
			err = apiImpl.removeDoc(sessCtx, projectItem, recycleItem.RecycleItemId)
			if err != nil {
				return nil, err
			}
		} else if recycleItem.RecycleItemType == uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_PAGES) {
			err = apiImpl.removePages(sessCtx, projectItem, recycleItem.RecycleItemId)
			if err != nil {
				return nil, err
			}
		} else if recycleItem.RecycleItemType == uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_BOARD) {
			err = apiImpl.removeBoard(sessCtx, projectItem, recycleItem.RecycleItemId)
			if err != nil {
				return nil, err
			}
		} else if recycleItem.RecycleItemType == uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_FILE) {
			err = apiImpl.removeFile(sessCtx, projectItem, recycleItem.RecycleItemId)
			if err != nil {
				return nil, err
			}
		} else if recycleItem.RecycleItemType == uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_API_COLL) {
			err = apiImpl.removeApiColl(sessCtx, projectItem, recycleItem.RecycleItemId)
			if err != nil {
				return nil, err
			}
		} else if recycleItem.RecycleItemType == uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_DATA_ANNO) {
			err = apiImpl.removeDataAnno(sessCtx, projectItem, recycleItem.RecycleItemId)
			if err != nil {
				return nil, err
			}
		}
		return &project_recycle_api.RemoveResponse{
			Code: project_recycle_api.RemoveResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addRemoveFromRecycleEvent(sessionItem, projectItem, req.RecycleItemId,
		project_recycle_api.RECYCLE_ITEM_TYPE(recycleItem.RecycleItemType), title, time.Now().UnixNano()/1e6)
	return ret.(*project_recycle_api.RemoveResponse), nil
}

func (apiImpl *ProjectRecycleApiImpl) removeIdea(ctx context.Context, projectItem *project_dao.ProjectInfoDbItem, recycleItemId string) error {
	err := idea_dao.IdeaRecycleDao.Remove(ctx, projectItem.ProjectId, recycleItemId)
	if err != nil {
		return err
	}
	//移除评价
	err = idea_dao.AppraiseDao.RemoveByIdea(ctx, recycleItemId)
	if err != nil {
		return err
	}
	return nil
}

func (apiImpl *ProjectRecycleApiImpl) removeRequirement(ctx context.Context, projectItem *project_dao.ProjectInfoDbItem, recycleItemId string) error {
	err := requirement_dao.RequirementRecycleDao.Remove(ctx, projectItem.ProjectId, recycleItemId)
	if err != nil {
		return err
	}
	//移除工单关联
	err = requirement_dao.LinkIssueInfoDao.RemoveByRequirement(ctx, projectItem.ProjectId, recycleItemId)
	if err != nil {
		return err
	}
	//移除相关评价
	err = requirement_dao.KanoInfoDao.Remove(ctx, recycleItemId)
	if err != nil {
		return err
	}
	err = requirement_dao.FourQInfoDao.Remove(ctx, recycleItemId)
	if err != nil {
		return err
	}
	//移除相关评论
	err = comment_dao.CommentDao.RemoveByTarget(ctx, projectItem.ProjectId, uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_REQUIRE_MENT), recycleItemId)
	if err != nil {
		return err
	}
	return nil
}

func (apiImpl *ProjectRecycleApiImpl) removeIssue(ctx context.Context, projectItem *project_dao.ProjectInfoDbItem, recycleItemId string, issueType project_issue_api.ISSUE_TYPE) error {
	err := issue_dao.IssueRecycleDao.Remove(ctx, projectItem.ProjectId, recycleItemId)
	if err != nil {
		return err
	}
	//移除子任务
	err = issue_dao.SubIssueDao.RemoveByIssue(ctx, projectItem.ProjectId, recycleItemId)
	if err != nil {
		return err
	}
	//移除评论
	targetType := project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_TASK
	if issueType == project_issue_api.ISSUE_TYPE_ISSUE_TYPE_BUG {
		targetType = project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_BUG
	}
	err = comment_dao.CommentDao.RemoveByTarget(ctx, projectItem.ProjectId, uint32(targetType), recycleItemId)
	if err != nil {
		return err
	}
	return nil
}

func (apiImpl *ProjectRecycleApiImpl) removeTestcase(ctx context.Context, projectItem *project_dao.ProjectInfoDbItem, recycleItemId string) error {
	err := testcase_dao.CaseRecycleDao.Remove(ctx, recycleItemId, projectItem.ProjectId)
	if err != nil {
		return err
	}
	err = dao.MsgDataDao.Remove(ctx, recycleItemId)
	if err != nil {
		return err
	}
	//移除评论
	err = comment_dao.CommentDao.RemoveByTarget(ctx, projectItem.ProjectId, uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_TEST_CASE), recycleItemId)
	if err != nil {
		return err
	}
	return nil
}

func (apiImpl *ProjectRecycleApiImpl) removeBulletin(ctx context.Context, projectItem *project_dao.ProjectInfoDbItem, recycleItemId string) error {
	err := bulletin_dao.BulletinRecycleDao.Remove(ctx, recycleItemId, projectItem.ProjectId)
	if err != nil {
		return err
	}
	err = dao.MsgDataDao.Remove(ctx, recycleItemId)
	if err != nil {
		return err
	}
	return nil
}

func (apiImpl *ProjectRecycleApiImpl) removeSprit(ctx context.Context, projectItem *project_dao.ProjectInfoDbItem, recycleItemId string) error {
	err := project_entry_dao.EntryRecycleDao.Remove(ctx, recycleItemId, projectItem.ProjectId)
	if err != nil {
		return err
	}
	err = issue_dao.IssueDao.ClearSprit(ctx, projectItem.ProjectId, recycleItemId)
	if err != nil {
		return err
	}
	err = issue_dao.SpritDao.Remove(ctx, projectItem.ProjectId, recycleItemId)
	if err != nil {
		return err
	}
	err = issue_dao.SpritStateDao.Remove(ctx, recycleItemId)
	if err != nil {
		return err
	}
	err = issue_dao.SummaryItemDao.RemoveBySprit(ctx, recycleItemId)
	if err != nil {
		return err
	}
	//移除评论
	err = comment_dao.CommentDao.RemoveByTarget(ctx, projectItem.ProjectId, uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_ENTRY), recycleItemId)
	if err != nil {
		return err
	}
	return nil
}

func (apiImpl *ProjectRecycleApiImpl) removeDoc(ctx context.Context, projectItem *project_dao.ProjectInfoDbItem, recycleItemId string) error {
	err := project_entry_dao.EntryRecycleDao.Remove(ctx, recycleItemId, projectItem.ProjectId)
	if err != nil {
		return err
	}
	err = project_doc_dao.DocContentDao.Remove(ctx, recycleItemId)
	if err != nil {
		return err
	}
	//删除历史
	err = project_doc_dao.ContentHistoryDao.RemoveByDoc(ctx, recycleItemId)
	if err != nil {
		return err
	}
	//移除评论
	err = comment_dao.CommentDao.RemoveByTarget(ctx, projectItem.ProjectId, uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_ENTRY), recycleItemId)
	if err != nil {
		return err
	}
	return nil
}

func (apiImpl *ProjectRecycleApiImpl) removePages(ctx context.Context, projectItem *project_dao.ProjectInfoDbItem, recycleItemId string) error {
	err := project_entry_dao.EntryRecycleDao.Remove(ctx, recycleItemId, projectItem.ProjectId)
	if err != nil {
		return err
	}
	//移除评论
	err = comment_dao.CommentDao.RemoveByTarget(ctx, projectItem.ProjectId, uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_ENTRY), recycleItemId)
	if err != nil {
		return err
	}
	return nil
}

func (apiImpl *ProjectRecycleApiImpl) removeBoard(ctx context.Context, projectItem *project_dao.ProjectInfoDbItem, recycleItemId string) error {
	err := project_entry_dao.EntryRecycleDao.Remove(ctx, recycleItemId, projectItem.ProjectId)
	if err != nil {
		return err
	}
	err = project_board_dao.NodeDao.RemoveByBoard(ctx, projectItem.ProjectId, recycleItemId)
	if err != nil {
		return err
	}
	err = project_board_dao.EdgeDao.RemoveByBoard(ctx, recycleItemId)
	if err != nil {
		return err
	}
	//移除评论
	err = comment_dao.CommentDao.RemoveByTarget(ctx, projectItem.ProjectId, uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_ENTRY), recycleItemId)
	if err != nil {
		return err
	}
	return nil
}

func (apiImpl *ProjectRecycleApiImpl) removeFile(ctx context.Context, projectItem *project_dao.ProjectInfoDbItem, recycleItemId string) error {
	err := project_entry_dao.EntryRecycleDao.Remove(ctx, recycleItemId, projectItem.ProjectId)
	if err != nil {
		return err
	}
	//移除评论
	err = comment_dao.CommentDao.RemoveByTarget(ctx, projectItem.ProjectId, uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_ENTRY), recycleItemId)
	if err != nil {
		return err
	}
	return nil
}

func (apiImpl *ProjectRecycleApiImpl) removeApiColl(ctx context.Context, projectItem *project_dao.ProjectInfoDbItem, recycleItemId string) error {
	entryItem, err := project_entry_dao.EntryRecycleDao.Get(ctx, recycleItemId, projectItem.ProjectId)
	if err != nil {
		return err
	}
	err = project_entry_dao.EntryRecycleDao.Remove(ctx, recycleItemId, projectItem.ProjectId)
	if err != nil {
		return err
	}
	if entryItem.ExtraApiCollInfo.ApiCollType == uint32(project_entry_api.API_COLL_TYPE_API_COLL_GRPC) {
		err = api_coll_dao.GrpcExtraDao.Remove(ctx, recycleItemId)
		if err != nil {
			return err
		}
	} else if entryItem.ExtraApiCollInfo.ApiCollType == uint32(project_entry_api.API_COLL_TYPE_API_COLL_OPENAPI) {
		err = api_coll_dao.OpenApiExtraDao.Remove(ctx, recycleItemId)
		if err != nil {
			return err
		}
	} else if entryItem.ExtraApiCollInfo.ApiCollType == uint32(project_entry_api.API_COLL_TYPE_API_COLL_CUSTOM) {
		err = api_coll_dao.CustomExtraDao.Remove(ctx, recycleItemId)
		if err != nil {
			return err
		}
		err = api_coll_dao.ApiGroupDao.RemoveByColl(ctx, recycleItemId)
		if err != nil {
			return err
		}
		err = api_coll_dao.ApiItemDao.RemoveByColl(ctx, recycleItemId)
		if err != nil {
			return err
		}
	}
	//移除评论
	err = comment_dao.CommentDao.RemoveByTarget(ctx, projectItem.ProjectId, uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_ENTRY), recycleItemId)
	if err != nil {
		return err
	}
	return nil
}

func (apiImpl *ProjectRecycleApiImpl) removeDataAnno(ctx context.Context, projectItem *project_dao.ProjectInfoDbItem, recycleItemId string) error {
	err := project_entry_dao.EntryRecycleDao.Remove(ctx, recycleItemId, projectItem.ProjectId)
	if err != nil {
		return err
	}
	//删除标注成员
	err = data_anno_dao.AnnoMemberDao.RemoveByAnnoProject(ctx, recycleItemId)
	if err != nil {
		return err
	}
	//删除标注资源
	err = data_anno_dao.ResourceDao.RemoveByAnnoProject(ctx, recycleItemId)
	if err != nil {
		return err
	}
	//删除任务
	err = data_anno_dao.AnnoTaskDao.RemoveByAnnoProject(ctx, recycleItemId)
	if err != nil {
		return err
	}
	//删除结果
	err = data_anno_dao.AnnoResultDao.RemoveByAnnoProject(ctx, recycleItemId)
	if err != nil {
		return err
	}
	//删除标注项目
	err = data_anno_dao.AnnoProjectDao.Remove(ctx, projectItem.ProjectId, recycleItemId)
	if err != nil {
		return err
	}
	//移除评论
	err = comment_dao.CommentDao.RemoveByTarget(ctx, projectItem.ProjectId, uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_ENTRY), recycleItemId)
	if err != nil {
		return err
	}
	return nil
}
